package com.diaohw.module.file.service.impl;

import cn.hutool.core.util.StrUtil;
import com.diaohw.module.file.mapper.AccountFileMapper;
import com.diaohw.module.file.mapper.CatalogMapper;
import com.diaohw.module.file.obj.dto.CatalogDTO;
import com.diaohw.module.file.obj.entity.CatalogDO;
import com.diaohw.module.file.obj.query.CatalogQuery;
import com.diaohw.module.file.obj.vo.CatalogTreeVo;
import com.diaohw.module.file.obj.vo.CatalogVO;
import com.diaohw.module.file.service.CatalogService;
import com.diaohw.platform.common.obj.page.PageResultVo;
import com.diaohw.platform.common.util.TreeUtil;
import com.diaohw.platform.framework.db.flex.DataCheckUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.diaohw.module.file.obj.tables.AccountFileDef.ACCOUNT_FILE;
import static com.diaohw.module.file.obj.tables.CatalogDef.CATALOG;
import static com.diaohw.platform.common.util.ValueUtil.STRING_ZERO;

/**
 * <p>
 * 目录 服务实现类
 * </p>
 *
 * @author D-Hw
 * @since 2024-11-05
 */
@Service
public class CatalogImpl implements CatalogService {

    @Resource
    private CatalogMapper catalogMapper;
    @Resource
    private AccountFileMapper accountFileMapper;

    @Override
    public CatalogVO create(CatalogDTO data) {


        DataCheckUtils.restrictiveInsert(CATALOG.PARENT_ID, data.getParentId(), CATALOG.CATALOG_NAME, data.getCatalogName(), catalogMapper);
        QueryWrapper wrapper = CatalogMapper.createWrapper(new CatalogQuery().setParentId(data.getParentId()));
        CatalogDO model = INSTANCE.dtoToEntity(data);
        int count = (int) catalogMapper.selectCountByQuery(wrapper) + 1;
        model.setSort(count);
        if (StrUtil.isBlank(data.getParentId())) {
            model.setParentId(STRING_ZERO);
        }
        catalogMapper.insert(model);
        return INSTANCE.entityToVo(model);
    }

    @Override
    public CatalogVO update(String id, CatalogDTO data) {

        DataCheckUtils.restrictiveUpdate(CATALOG.ID, id, CATALOG.PARENT_ID, data.getParentId(), CATALOG.CATALOG_NAME, data.getCatalogName(), catalogMapper);

        CatalogDO model = INSTANCE.dtoToEntity(data);
        model.setId(id);

        catalogMapper.update(model);
        return INSTANCE.entityToVo(model);
    }

    @Override
    public Boolean delete(String id) {
        return catalogMapper.deleteById(id) > 0;
    }

    @Override
    public CatalogVO detail(String id) {
        CatalogDO model = catalogMapper.selectOneById(id);
        return INSTANCE.entityToVo(model);
    }

    @Override
    public List<CatalogVO> findByList(CatalogQuery query) {
        QueryWrapper wrapper = CatalogMapper.createWrapper(query);
        List<CatalogDO> list = catalogMapper.selectListByQuery(wrapper);
        return INSTANCE.entityToVo(list);
    }

    @Override
    public PageResultVo<CatalogVO> findByPage(CatalogQuery query) {
        QueryWrapper wrapper = CatalogMapper.createWrapper(query);
        Page<CatalogDO> page = catalogMapper.paginate(query.getPageIndex(), query.getPageSize(), wrapper);
        List<CatalogVO> list = INSTANCE.entityToVo(page.getRecords());
        return PageResultVo.create(page.getTotalRow(), list);
    }


    @Override
    public List<CatalogTreeVo> tree(CatalogQuery query) {
        QueryWrapper wrapper = CatalogMapper.createWrapper(query);
        wrapper.orderBy(CatalogDO::getParentId, Boolean.TRUE);
        wrapper.orderBy(CatalogDO::getSort, Boolean.TRUE);
        List<CatalogTreeVo> list = INSTANCE.toTree(catalogMapper.selectListByQuery(wrapper));

        List<CatalogTreeVo> tree = TreeUtil.listToTree(list, CatalogTreeVo::getId, CatalogTreeVo::getParentId, CatalogTreeVo::getChildren);
        if (Boolean.TRUE.equals(query.getFileCount())) {
            Map<String, Integer> catalogCount = fileCount();
            Map<String, CatalogTreeVo> treeMap = new HashMap<>();
            list.forEach(l -> {
                l.setFileCount(catalogCount.getOrDefault(l.getId(), 0));
                treeMap.put(l.getId(), l);
            });

            list.forEach(l -> calc(l, l.getFileCount(), treeMap));
        }
        return tree;
    }

    private Map<String, Integer> fileCount() {
        QueryWrapper wrapper = QueryWrapper.create();
        wrapper.select(ACCOUNT_FILE.CATALOG_ID,
                        QueryMethods.count().as("number"))
                .groupBy(ACCOUNT_FILE.CATALOG_ID);
        return accountFileMapper.selectListByQueryAs(wrapper, CatalogTreeVo.FileCountBO.class).stream()
                .collect(Collectors.toMap(CatalogTreeVo.FileCountBO::getCatalogId, CatalogTreeVo.FileCountBO::getNumber));
    }

    private void calc(CatalogTreeVo tree, int factor, Map<String, CatalogTreeVo> treeMap) {
        if (factor == 0 || !treeMap.containsKey(tree.getParentId())) {
            return;
        }
        CatalogTreeVo parent = treeMap.get(tree.getParentId());
        int count = parent.getFileCount() + factor;
        parent.setFileCount(count);
        calc(parent, factor, treeMap);
    }


}
